package com.example.tool;

import com.alibaba.fastjson2.JSONObject;
import com.example.tool.ck.ClickhouseConfig;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXDatePicker;
import io.datafx.controller.ViewController;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.chart.*;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.util.Pair;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.annotation.PostConstruct;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Function;

@ViewController(value = "/fxml/clickhouse.fxml", title = "ck")
public class CkController {

    @FXML
    private HBox qps5minBox;

    @FXML
    private JFXButton refreshBtn;
    @FXML
    private JFXDatePicker startTimePicker;
    @FXML
    private JFXDatePicker endTimePicker;

    @FXML
    private JFXCheckBox checkBoxMax;

    @FXML
    private JFXCheckBox checkBoxM90;

    @FXML
    private JFXCheckBox checkBoxAvg;

    private static final Function<LocalDate, Date> localDateDateFunction = localDate -> {
        String value = localDate.toString();
        try {
            return new SimpleDateFormat("yyyy-MM-dd").parse(value);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    };
    private static final Function<Pair<Date, LocalTime>, Date> localTimeFunction = pair -> {
        Date date = pair.getKey();
        String time = pair.getValue().toString();
        String timeStr = new SimpleDateFormat("yyyy-MM-dd").format(date) + " " + time;
        try {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(timeStr);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    };
    private static JdbcTemplate clickhouseTemplate;
    // 自定义的时间轴标签格式化器
    //@PostConstruct
    public void initialize() throws ParseException {
        clickhouseTemplate = new ClickhouseConfig().clickhouseTemplate();
        //2024-09-12 16:00:00 2024-09-13 16:00:00
        startTimePicker.setValue(LocalDate.now());
        endTimePicker.setValue(LocalDate.now());

        Date beginDate = localDateDateFunction.apply(startTimePicker.getValue());
        Date endDate = localDateDateFunction.apply(endTimePicker.getValue());
        checkBoxMax.setSelected(true);
        checkBoxM90.setSelected(true);
        checkBoxAvg.setSelected(true);
        refreshChart(beginDate,endDate);


        refreshBtn.setOnAction(event -> {
           // String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            try {
                Date beginDate1 = localDateDateFunction.apply(startTimePicker.getValue());
                Date endDate1 = localDateDateFunction.apply(endTimePicker.getValue());
                refreshChart(beginDate1,endDate1);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        });
    }

    public String getBeforeDay(String date) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date taskDate =simpleDateFormat.parse(date);
        Date beforeDate = new Date(taskDate.getTime() - 24 * 3600L * 1000);
        return simpleDateFormat.format(beforeDate);
    }

    private void refreshChart(Date begin,Date end) throws ParseException {
        Map<String,List<JSONObject>> dataMap  = new LinkedHashMap<>();
        List<String> dates = getDates(begin, end);
        int size = dates.size();
        for (String date : dates) {
            String beforeDay = getBeforeDay(date);
            String sql = "select max(ProfileEvent_Query)           max_qps,\n" +
                    "       round(avg(ProfileEvent_Query), 2) avg_qps,\n" +
                    "       round(quantile(0.90)(ProfileEvent_Query),2) m9_qps,\n" +
                    "       toStartOfTenMinutes(event_time)         max_event_time\n" +
                    " from system.metric_log\n" +
                    " where event_date >= addDays(today(), -"+size+")\n" +
                    "  and event_time >= '"+beforeDay+" 16:00:00'\n" +
                    "  and event_time < '"+date+" 16:00:00'\n" +
                    " group by toStartOfTenMinutes(event_time) \n" +
                    " order by max_event_time asc";
            System.out.println(sql);
            List<JSONObject> data = clickhouseTemplate.query(sql, (rs, rowNum) -> {
                JSONObject object = new JSONObject();
                int maxQps = rs.getInt(1);
                double avgQps = rs.getDouble(2);
                double m90Qps = rs.getDouble(3);
                Timestamp timestamp = rs.getTimestamp(4);
                object.put(date+"-maxQps", maxQps);
                object.put(date+"-avgQps", avgQps);
                object.put(date+"-m90Qps", m90Qps);
                object.put("time", timestamp.getTime());
                return object;
            });
            dataMap.put(date,data);
        }


        final CategoryAxis xAxis = new CategoryAxis();//定义一个x轴(数字横轴)
        final NumberAxis yAxis = new NumberAxis();//定义一个y轴(数字纵轴)
        xAxis.setLabel(String.join(",",dates)+" 时间");
        yAxis.setLabel("qps");
        LineChart<String, Number> barChart = new LineChart<>(xAxis, yAxis);
        javafx.scene.control.Label label = new javafx.scene.control.Label();
        label.setId("showLabelId");
        label.setStyle("-fx-font-size: 15;");
        label.setWrapText(true);
        label.setTextFill(Color.BLUE);
        label.setPrefWidth(300);

        boolean max = checkBoxMax.isSelected();
        boolean m90 = checkBoxM90.isSelected();
        boolean avg = checkBoxAvg.isSelected();
        for (Map.Entry<String, List<JSONObject>> entry : dataMap.entrySet()) {
            String dt = entry.getKey();
            List<JSONObject> vs = entry.getValue();
            if(max){
                addSeries(barChart, vs, dt+"-maxQps",label);
            }
            if(m90){
                addSeries(barChart, vs, dt+"-m90Qps", label);
            }
            if(avg){
                addSeries(barChart, vs, dt+"-avgQps", label);
            }
        }
        barChart.setPrefHeight(1200);
        barChart.setPrefWidth(2500);
        qps5minBox.getChildren().removeIf(x->true);
        qps5minBox.getChildren().addAll(barChart,label);
    }

    private List<String> getDates(Date begin, Date end) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String b = dateFormat.format(begin);
        String e = dateFormat.format(end);
        if(b.equals(e)){
            return Collections.singletonList(b);
        }
        ArrayList<String> dates = new ArrayList<>();
        dates.add(b);
        while (!b.equals(e)){
            b = dateFormat.format(new Date(dateFormat.parse(b).getTime()+24*3600L*1000));
            dates.add(b);
        }
        if(!dates.contains(e)){
            dates.add(e);
        }
        return dates;
    }

    private void addSeries(LineChart<String, Number> barChart, List<JSONObject> data, String maxQps, Label label) {
        XYChart.Series<String, Number> qpsSeries = new XYChart.Series<>();
        qpsSeries.setName(maxQps);
        for (JSONObject bucket : data) {
            int qps = bucket.getInteger(maxQps);
            long time = bucket.getLong("time");
            JSONObject extra = new JSONObject();
            extra.put("x",new SimpleDateFormat("HH:mm").format(new Date(time)));
            extra.put("y",qps);
            qpsSeries.getData().add(new XYChart.Data<>(new SimpleDateFormat("HH:mm").format(new Date(time)), qps,
                    extra));
        }
        barChart.getData().add(qpsSeries);
        for (XYChart.Data<String, Number> datum : qpsSeries.getData()) {
            JSONObject extraValue = (JSONObject) datum.getExtraValue();
            datum.getNode().setOnMousePressed(event -> {
                label.setTranslateX(event.getSceneX()-barChart.getWidth());
                label.setTranslateY(event.getSceneY());

                label.setText("x:" + extraValue.get("x") + "\n"+maxQps+":" + extraValue.get("y"));
            });

        }
    }
}
